module sync_fifo #(
    parameter DSIZE = 8,
    parameter ASIZE = 4,     //$clog2(MEMSIZE),
    parameter MEMSIZE = 16
)(
    input clk,
    input rst,
    // write port
    input wval, // write valid
    input [DSIZE-1:0] wdata,
    output reg full,
    // read port
    input ren, // read enable
    output reg [DSIZE-1:0] rdata,
    output reg empty
);
    reg [DSIZE-1:0] mem [MEMSIZE-1:0];
    reg [ASIZE-1:0] rd_ptr_f;
    reg [ASIZE-1:0] rd_ptr_next;
    reg [ASIZE-1:0] wr_ptr_f;
    reg [ASIZE-1:0] wr_ptr_next;
    reg [ASIZE:0] mem_count_f;
    reg [ASIZE:0] mem_count_next;

    always@(*) begin
        empty=mem_count_f==0;
        full=mem_count_f==MEMSIZE;
    end

    always@(*) begin
        if(rst) begin
            mem_count_next=0;
        end else if (wval&!full&ren&!empty) begin
            mem_count_next=mem_count_f;
        end else if (wval& !full) begin
            mem_count_next=mem_count_f+1;
        end else if (ren & !empty) begin
            mem_count_next=mem_count_f-1;
        end else begin
            mem_count_next=mem_count_f;
        end
    end
    always@(posedge clk) begin
        mem_count_f<=mem_count_next;
    end
    
    always@(*) begin
        if(rst)
            rd_ptr_next=0;
        else if(ren & !empty)
            rd_ptr_next=rd_ptr_f+1;
        else
            rd_ptr_next=rd_ptr_f;
    end
    always@(posedge clk) begin
        rd_ptr_f<=rd_ptr_next;
    end
    always@(posedge clk) begin
        if(rst)
            rdata<=0;
        else if(ren & !empty)
            rdata<=mem[rd_ptr_f];
    end

    always@(*) begin
        if(rst)
            wr_ptr_next=0;
        else if(wval & !full)
            wr_ptr_next=wr_ptr_f+1;
        else 
            wr_ptr_next=wr_ptr_f;
    end
    always@(posedge clk) begin
        wr_ptr_f<=wr_ptr_next;
    end
    always@(posedge clk) begin
        if(wval & !full)
            mem[wr_ptr_f]<=wdata;
    end
endmodule

